home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 176-200 / scopedisk177 / fragit / fragit.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  31KB  |  1,011 lines

  1. /* --------------------------------------------------------------------
  2.  
  3.        Fragit -- A simple memory thrasher/debugging tool.
  4.  
  5.   Copyright © 1989 Justin V. McCormick.  All Rights Reserved.
  6.  
  7.      Thanks to Bryce Nesbitt for bug fixes and suggestions.
  8.  
  9.  
  10. Notices:
  11.  
  12.   This code may be freely used, modified, and distributed in any
  13. form for either commercial or personal profit or non-profit, so
  14. long as this copyright notice remains prominently attached to
  15. the source code.
  16.  
  17.   In any case, the author makes no specific performance claims
  18. for this code and assumes no responsibility to maintain or
  19. support this code.  Additionally, the author bears no liability
  20. or responsibility should the use of this code result in loss of
  21. data or sleep.  This is your final notice - you've been warned!
  22.  
  23.  
  24. Modification History:
  25.  
  26. V1.0 88-12-27 - Buggy original version released.
  27. V1.1 89-04-01 - Fixed Exec list bug (thanks Bryce!). Never released.
  28. V2.0 89-07-04 - Many enhancements, added gadgets, Workbench support.
  29.  
  30. -------------------------------------------------------------------- */
  31.  
  32. /* Includes */
  33. #include <exec/types.h>
  34. #include <exec/nodes.h>
  35. #include <exec/lists.h>
  36. #include <exec/memory.h>
  37. #include <exec/ports.h>
  38. #include <exec/io.h>
  39. #include <exec/libraries.h>
  40. #include <exec/interrupts.h>
  41. #include <exec/semaphores.h>
  42. #include <graphics/gfx.h>
  43. #include <graphics/view.h>
  44. #include <graphics/rastport.h>
  45. #include <graphics/layers.h>
  46. #include <graphics/clip.h>
  47. #include <graphics/text.h>
  48. #include <libraries/dos.h>
  49. #include <devices/timer.h>
  50. #include <devices/inputevent.h>
  51. #include <intuition/intuition.h>
  52. #include <intuition/intuitionbase.h>
  53. #include <workbench/workbench.h>
  54. #include <workbench/startup.h>
  55.  
  56. /* Special defines for Gimpel Lint */
  57. #ifdef _lint
  58. #define LATTICE 1
  59. #define __stdargs
  60. #define __regargs
  61. #define __fARGS(a) ()
  62. #else
  63. #ifdef LATTICE
  64. #define __fARGS(a) a
  65. #endif
  66. #endif
  67.  
  68. #include <stdio.h>
  69. #include <ctype.h>
  70.  
  71. /* Lattice 5.02 or later specifics */
  72. #ifdef LATTICE
  73. #include <string.h>
  74. #include <stdlib.h>
  75. #include <proto/exec.h>
  76. #include <proto/graphics.h>
  77. #include <proto/intuition.h>
  78. #include <proto/dos.h>
  79. #include <proto/icon.h>
  80. #endif
  81.  
  82. /* Manx 3.6a or later specifics */
  83. #ifdef AZTEC_C
  84. #include <functions.h>
  85. #ifdef _lint
  86. #define __ARGS(a) a
  87. #else
  88. #define __ARGS(a) ()
  89. #define __fARGS(a) ()
  90. #define __stdargs
  91. #define __regargs
  92. #endif
  93. extern int strlen __ARGS((BYTE *));
  94. extern LONG atol __ARGS((BYTE *));
  95. extern VOID exit __ARGS((int));
  96. extern VOID printf __ARGS((BYTE *, BYTE *, ));
  97. extern VOID sprintf __ARGS((BYTE *, BYTE *, ));
  98. extern struct IORequest *CreateExtIO __ARGS((struct MsgPort *, LONG));
  99. #endif
  100.  
  101. /* From amiga.lib (or c.lib in Manx) */
  102. extern struct Library *IconBase;
  103. extern ULONG __stdargs RangeRand __ARGS((ULONG));
  104.  
  105. /* Local Structure Definitions */
  106. struct FragNode            /* For dynamic list of memory blocks    */
  107. {
  108.   struct MinNode fn_Node;    /* Exec node linkage            */
  109.   ULONG fn_Size;        /* Size of allocated block        */
  110.   BYTE *fn_Data;        /* Pointer to allocated block        */
  111. };
  112. /* Easy access for struct size */
  113. #define FSIZE sizeof (struct FragNode)
  114.  
  115. /* Local CODE */
  116. LONG AddRandomFrag __ARGS((struct MinList *, LONG, LONG));
  117. LONG CreateVBTimer __ARGS((BYTE *, struct MsgPort **, struct timerequest **));
  118. LONG FreeRandomFrag __ARGS((struct MinList *));
  119. struct FragNode *AllocFragNode __ARGS((LONG));
  120. struct MinList *AllocMinList __ARGS((VOID));
  121. VOID AbortAsyncIO __ARGS((struct MsgPort *, struct IORequest *));
  122. VOID AllocAllMem __ARGS((struct MinList *, LONG));
  123. VOID CleanUp __ARGS((LONG));
  124. VOID DoFragBoolGad __ARGS((struct Gadget *));
  125. VOID DoFragIDCMP __ARGS((VOID));
  126. VOID DoFragStringGad __ARGS((struct Gadget *));
  127. VOID FreeAllFragNodes __ARGS((struct MinList *));
  128. VOID FreeFragNode __ARGS((struct FragNode *));
  129. VOID FreeFSVBDelay __ARGS((VOID));
  130. VOID FreeMinList __ARGS((struct MinList *));
  131. VOID FreeVBTimer __ARGS((struct MsgPort **, struct timerequest **));
  132. VOID InitTimer __ARGS((VOID));
  133. VOID main __ARGS((int, BYTE **));
  134. VOID ParseToolTypes __ARGS((BYTE *));
  135. VOID PrintMemoryStats __ARGS((VOID));
  136. VOID RattleDice __ARGS((VOID));
  137. VOID SetMicroTimer __ARGS((LONG));
  138. VOID ThrashMem __ARGS((LONG, LONG, LONG));
  139.  
  140. /* Global DATA */
  141. struct GfxBase *GfxBase;
  142. struct IntuitionBase *IntuitionBase;
  143. struct MinList *FragList;
  144. struct MsgPort *TimerPort1;     /* Micro timer events come here        */
  145. struct timerequest *STimeReq;    /* Short delay timer request        */
  146. struct Window *FragWin;
  147.  
  148. /* Gadgets and associated baggage */
  149. struct TextAttr Def8Text =
  150. {
  151.   (UBYTE *)"topaz.font",    /* Font Name   */
  152.   8,                /* Font Height */
  153.   FS_NORMAL,            /* Style       */
  154.   FPF_ROMFONT            /* Preferences */
  155. };
  156.  
  157. /* -------------------------------------------------------------------- */
  158. #define NWWIDE 255        /* Window width */
  159. #define NWHIGH 152        /* Window height */
  160.  
  161. #define FHDTL    8
  162. #define FHDTT    28
  163.  
  164. #define FDLGL    32        /* Left edge of first string gadget */
  165. #define FDLGT    (FHDTT+60)    /* Top edge of first string gadget */
  166.  
  167. #define FDLW    (9*8)        /* 9 char wide string gadgets */
  168. #define FDLH    8        /* Height of string gadgets */
  169. #define FDSPC    50        /* Spacing between string gadgets */
  170.  
  171. #define FHDL (FHDTL - (FDLGL + FDLW + FDSPC))
  172. #define FHDT (FHDTT - (FDLGT + FDLH + 36))
  173.  
  174.  
  175. #define FGLEFT    8
  176. #define FGTOP    135
  177. #define FGWIDE    51
  178. #define FGHIGH    13
  179.  
  180. /* -------------------------------------------------------------------- */
  181. UBYTE OldBinStr[12];        /* Shared undo space for string gadgets */
  182.  
  183. WORD BinBData[] = { 0,0, FDLW+5,0, FDLW+5,FDLH+4, 0,FDLH+4, 0,0 };
  184. struct Border BinBorder = { -3, -3, 1, 0, JAM2, 5, BinBData, 0L };
  185.  
  186. /* -------------------------------------------------------------------- */
  187. struct Image FGadBlk1 = { 1, 1, FGWIDE-2, FGHIGH-2, 0, 0L,  0,  1, 0L };
  188. struct Image FGadBlk0 = { 0, 0, FGWIDE, FGHIGH, 0, 0L,  0,  3, &FGadBlk1 };
  189.  
  190. /* -------------------------------------------------------------------- */
  191. UBYTE FPurgeStr[] = "PURGE";
  192. struct IntuiText FPurgeTxt = { 0, 1, JAM1, 6, 3, &Def8Text, FPurgeStr, 0L };
  193. struct Gadget FPurgeGad =
  194. {
  195.   0L, FGLEFT+3*(FGWIDE+10)+5, FGTOP, FGWIDE, FGHIGH, GADGHCOMP | GADGIMAGE,
  196.   RELVERIFY, BOOLGADGET, (APTR)&FGadBlk0, 0L, &FPurgeTxt, 0L, 0L, 23, 0L
  197. };
  198.  
  199. /* -------------------------------------------------------------------- */
  200. UBYTE FAllocStr[] = "ALLOC";
  201. struct IntuiText FAllocTxt = { 0, 1, JAM1, 6, 3, &Def8Text, FAllocStr, 0L };
  202. struct Gadget FAllocGad =
  203. {
  204.   &FPurgeGad, FGLEFT+2*(FGWIDE+10)+5, FGTOP, FGWIDE, FGHIGH, GADGHCOMP | GADGIMAGE,
  205.   RELVERIFY, BOOLGADGET, (APTR)&FGadBlk0, 0L, &FAllocTxt, 0L, 0L, 22, 0L
  206. };
  207.  
  208. /* -------------------------------------------------------------------- */
  209. UBYTE FStartStr[] = "START";
  210. struct IntuiText FStartTxt = { 0, 1, JAM1, 6, 3, &Def8Text, FStartStr, 0L };
  211. struct Gadget FStartGad =
  212. {
  213.   &FAllocGad, FGLEFT+(FGWIDE+10), FGTOP, FGWIDE, FGHIGH, GADGHCOMP | GADGIMAGE,
  214.   RELVERIFY, BOOLGADGET, (APTR)&FGadBlk0, 0L, &FStartTxt, 0L, 0L, 21, 0L
  215. };
  216.  
  217. /* -------------------------------------------------------------------- */
  218. UBYTE FStopStr[] = "STOP";
  219. struct IntuiText FStopTxt = { 0, 1, JAM1, 10, 3, &Def8Text, FStopStr, 0L };
  220. struct Gadget FStopGad =
  221. {
  222.   &FStartGad, FGLEFT, FGTOP, FGWIDE, FGHIGH, GADGHCOMP | GADGIMAGE,
  223.   RELVERIFY, BOOLGADGET, (APTR)&FGadBlk0, 0L, &FStopTxt, 0L, 0L, 20, 0L
  224. };
  225.  
  226. /* -------------------------------------------------------------------- */
  227. UBYTE FHeaderLbl4[] = "total";
  228. struct IntuiText FHeaderTxt4 = { 3, 0, JAM2, FHDL+20, FHDT+50, &Def8Text, FHeaderLbl4, 0L };
  229.  
  230. UBYTE FHeaderLbl3[] = "fast";
  231. struct IntuiText FHeaderTxt3 = { 3, 0, JAM2, FHDL+20, FHDT+40, &Def8Text, FHeaderLbl3, &FHeaderTxt4 };
  232.  
  233. UBYTE FHeaderLbl2[] = "chip";
  234. struct IntuiText FHeaderTxt2 = { 3, 0, JAM2, FHDL+20, FHDT+30, &Def8Text, FHeaderLbl2, &FHeaderTxt3 };
  235.  
  236. UBYTE FHeaderLbl1[] = "Type  Available   Largest";
  237. struct IntuiText FHeaderTxt1 = { 3, 0, JAM2, FHDL+20, FHDT+20, &Def8Text, FHeaderLbl1, &FHeaderTxt2 };
  238.  
  239. UBYTE FHeaderLbl0[] = "Fragments  Failures  Allocated"; 
  240. struct IntuiText FHeaderTxt0 = { 3, 0, JAM2, FHDL, FHDT, &Def8Text, FHeaderLbl0, &FHeaderTxt1 };
  241.  
  242. /* -------------------------------------------------------------------- */
  243. UBYTE FMaxFragLbl[]  = "Max Frag Size";
  244. UBYTE FMaxFragStr[12];
  245. struct StringInfo FMaxFragStrInfo =
  246. {
  247.   (UBYTE *)FMaxFragStr, (UBYTE *)OldBinStr, 0, 9, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L
  248. };
  249. struct IntuiText FMaxFragTxt0 = { 3, 0, JAM2, -15, -13, &Def8Text, FMaxFragLbl, &FHeaderTxt0 };
  250. struct Gadget FMaxFragGad =
  251. {
  252.   &FStopGad, FDLGL+(FDLW+FDSPC), FDLGT+(FDLH+20), FDLW, FDLH, GADGHCOMP,
  253.   RELVERIFY | LONGINT | STRINGCENTER, STRGADGET,
  254.   (APTR)&BinBorder, 0L, &FMaxFragTxt0, 0L, (APTR)&FMaxFragStrInfo, 13, 0L
  255. };
  256. /* -------------------------------------------------------------------- */
  257. UBYTE FMinFragLbl[]  = "Min Frag Size";
  258. UBYTE FMinFragStr[12];
  259. struct StringInfo FMinFragStrInfo =
  260. {
  261.   (UBYTE *)FMinFragStr, (UBYTE *)OldBinStr, 0, 9, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L
  262. };
  263. struct IntuiText FMinFragTxt0 = { 3, 0, JAM2, -15, -13, &Def8Text, FMinFragLbl, 0L };
  264. struct Gadget FMinFragGad =
  265. {
  266.   &FMaxFragGad, FDLGL, FDLGT+(FDLH+20), FDLW, FDLH, GADGHCOMP,
  267.   RELVERIFY | LONGINT | STRINGCENTER, STRGADGET,
  268.   (APTR)&BinBorder, 0L, &FMinFragTxt0, 0L, (APTR)&FMinFragStrInfo, 12, 0L
  269. };
  270. /* -------------------------------------------------------------------- */
  271. UBYTE FAllocSpeedLbl[]  = "Timer Speed";
  272. UBYTE FAllocSpeedStr[12];
  273. struct StringInfo FAllocSpeedStrInfo =
  274. {
  275.   (UBYTE *)FAllocSpeedStr, (UBYTE *)OldBinStr, 0, 9, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L
  276. };
  277. struct IntuiText FAllocSpeedTxt0 = { 3, 0, JAM2, -7, -13, &Def8Text, FAllocSpeedLbl, 0L };
  278. struct Gadget FAllocSpeedGad =
  279. {
  280.   &FMinFragGad, FDLGL+(FDLW+FDSPC), FDLGT, FDLW, FDLH, GADGHCOMP,
  281.   RELVERIFY | LONGINT | STRINGCENTER, STRGADGET,
  282.   (APTR)&BinBorder, 0L, &FAllocSpeedTxt0, 0L, (APTR)&FAllocSpeedStrInfo, 11, 0L
  283. };
  284. /* -------------------------------------------------------------------- */
  285. UBYTE FMinMemLbl[]  = "Low Mem Limit";
  286. UBYTE FMinMemStr[12];
  287. struct StringInfo FMinMemStrInfo =
  288. {
  289.   (UBYTE *)FMinMemStr, (UBYTE *)OldBinStr, 0, 9, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L
  290. };
  291. struct IntuiText FMinMemTxt0 = { 3, 0, JAM2, -15, -13, &Def8Text, FMinMemLbl, 0L };
  292. struct Gadget FMinMemGad =
  293. {
  294.   &FAllocSpeedGad, FDLGL, FDLGT, FDLW, FDLH, GADGHCOMP,
  295.   RELVERIFY | LONGINT | STRINGCENTER, STRGADGET,
  296.   (APTR)&BinBorder, 0L, &FMinMemTxt0, 0L, (APTR)&FMinMemStrInfo, 10, 0L
  297. };
  298.  
  299. UBYTE FragWinTitle[] = "Fragit 2.0 by JVM";
  300. UBYTE Author[] = "Copyright \251 1989 by Justin V. McCormick 89-07-25";
  301.  
  302. struct NewWindow NewFragWin =
  303. {
  304.   0,11, NWWIDE,NWHIGH, 0,1, CLOSEWINDOW | VANILLAKEY | GADGETUP,
  305.   WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | NOCAREREFRESH,
  306.   &FMinMemGad, 0, FragWinTitle, 0, 0, 0,0, 0,0, WBENCHSCREEN
  307. };
  308. BYTE LongFmtStr[] = "%ld";
  309.  
  310. LONG AllocCount;        /* Number of FragNodes in list        */
  311. LONG FailCount;            /* Number of allocs that failed     */
  312. LONG FAllocSpeed;        /* Timer delay between thrashings    */
  313. LONG FMaxFrag;            /* Maximum fragment size        */
  314. LONG FMinFrag;            /* Minimum fragment size        */
  315. LONG FMinMem;            /* Minimum memory limit            */
  316. LONG FragDone;            /* Global "Done" flag            */
  317. LONG FragGoFlag;        /* 0=Stop,1=GO                */
  318. LONG TotalFragBytes;        /* Number of bytes due to fn_Data frags    */
  319. ULONG FragIDCMPMask;        /* Precomp FragWin UserPort bitmask    */
  320. ULONG FragTimerMask;        /* Precomp FragTimer UserPort bitmask    */
  321. ULONG FMemType;            /* Type of memory to allocate        */
  322.  
  323. /* --------------------------------------------------------------------
  324.  * Free memory allocated to a MinList structure, if allocated.
  325.  * -------------------------------------------------------------------- */
  326. VOID FreeMinList (list)
  327.   struct MinList *list;
  328. {
  329.   if (list != 0)
  330.     FreeMem ((VOID *) list, (LONG) sizeof (struct MinList));
  331. }
  332.  
  333. /* --------------------------------------------------------------------
  334.  * Free memory allocated to a FragNode structure, if allocated.
  335.  * -------------------------------------------------------------------- */
  336. VOID FreeFragNode (mnode)
  337.   struct FragNode *mnode;
  338. {
  339.   if (mnode != 0)
  340.     FreeMem ((VOID *) mnode, (LONG)mnode->fn_Size);
  341. }
  342.  
  343. /* --------------------------------------------------------------------
  344.  * Walk list of allocated FragNodes in a MinList and free each one,
  345.  * then deallocate the MinList itself.
  346.  * -------------------------------------------------------------------- */
  347. VOID FreeAllFragNodes (list)
  348.   struct MinList *list;
  349. {
  350.   struct FragNode *tnode;
  351.  
  352.   if (list != 0)
  353.   {
  354.     while ((tnode = (struct FragNode *) RemHead ((struct List *)list)) != 0)
  355.     {
  356.       FreeFragNode (tnode);
  357.     }
  358.   }
  359. }
  360.  
  361. /* --------------------------------------------------------------------
  362.  * Clean out any pending async IO in a given IORequest type struct.
  363.  * Make sure the port signal bit is cleared.
  364.  * --------------------------------------------------------------------    */
  365. VOID AbortAsyncIO (port, req)
  366.   struct MsgPort *port;
  367.   struct IORequest *req;
  368. {
  369.   if (req->io_Command != 0 && CheckIO (req) == 0)
  370.   {
  371.     (VOID)AbortIO (req);
  372.     (VOID)WaitIO (req);
  373.   }
  374.   (VOID) SetSignal (0L, (LONG)(1L << port->mp_SigBit));
  375. }
  376.  
  377. /* -------------------------------------------------------------------- */
  378. VOID FreeVBTimer (pport, ptreq)
  379.   struct MsgPort **pport;
  380.   struct timerequest **ptreq;
  381. {
  382.   struct timerequest *treq;
  383.  
  384.   if (*pport != 0)
  385.   {
  386.     if ((treq = *ptreq) != 0)
  387.     {
  388.       if (treq->tr_node.io_Device != 0)
  389.       {
  390.         AbortAsyncIO (*pport, (struct IORequest *)treq);
  391.         CloseDevice ((struct IORequest *)treq);
  392.       }
  393.       DeleteExtIO ((struct IORequest *)treq);
  394.       *ptreq = 0;
  395.     }
  396.     DeletePort (*pport);
  397.     *pport = 0;
  398.   }
  399. }
  400.  
  401. /* --------------------------------------------------------------------
  402.  * Universal exit point for entire program.
  403.  * -------------------------------------------------------------------- */
  404. VOID CleanUp (exitcode)
  405.   LONG exitcode;
  406. {
  407.   FreeVBTimer (&TimerPort1, &STimeReq);
  408.   if (FragWin != 0)
  409.     CloseWindow (FragWin);
  410.   FreeAllFragNodes (FragList);
  411.   FreeMinList (FragList);
  412.   if (IntuitionBase != 0)
  413.     CloseLibrary ((struct Library *)IntuitionBase);
  414.   if (GfxBase != 0)
  415.     CloseLibrary ((struct Library *)GfxBase);
  416.   exit ((int)exitcode);
  417. }
  418.  
  419. /* --------------------------------------------------------------------
  420.  * Allocate and initialize a FragNode structure, return pointer or 0L
  421.  * -------------------------------------------------------------------- */
  422. struct FragNode *AllocFragNode (datasize)
  423.   LONG datasize;
  424. {
  425.   struct FragNode *mnode;
  426.  
  427.   mnode = (struct FragNode *) AllocMem ((LONG)datasize, (LONG)FMemType);
  428.   if (mnode != 0)
  429.   {
  430.     mnode->fn_Size = (ULONG)datasize;
  431.  
  432. #ifdef NOTREALLYNEEDED
  433.     mnode->fn_Data = (BYTE *)((LONG)mnode + FSIZE);
  434. #endif
  435.  
  436.   }
  437.   return (mnode);
  438. }
  439.  
  440. /* --------------------------------------------------------------------
  441.  * Given pointer to MinList and a maximum fragment size, allocate a
  442.  * FragNode with a fragment size minfrag <= size <= maxfrag and insert
  443.  * it at the head of the FragNode list.    Return actual size of fragment.
  444.  * -------------------------------------------------------------------- */
  445. LONG AddRandomFrag(list, minfrag, maxfrag)
  446.   struct MinList *list;
  447.   LONG minfrag, maxfrag;
  448. {
  449.   struct FragNode *tnode;
  450.   LONG tsize;
  451.  
  452.   if (minfrag >= maxfrag)
  453.     tsize = minfrag;
  454.   else
  455.     tsize = (LONG) RangeRand ((ULONG) (maxfrag - minfrag)) + minfrag;
  456.  
  457. /* Alloc a random sized node */
  458.   if ((tnode = AllocFragNode (tsize)) != 0)
  459.   {
  460.     AddHead ((struct List *)list, (struct Node *)tnode);
  461. #ifdef DEBUGIT
  462.     printf("Adding a %7ld byte frag SUCCEEDED\n", tsize);
  463. #endif
  464.     AllocCount++;
  465.     TotalFragBytes += tsize;
  466.     return (tsize);
  467.   }
  468.   else
  469.   {
  470. #ifdef DEBUGIT
  471.     printf("Adding a %7ld byte frag FAILED!\n", tsize);
  472. #endif
  473.     FailCount++;
  474.     return (0L);
  475.   }
  476. }
  477.  
  478. /* --------------------------------------------------------------------
  479.  * Given a pointer to a MinList of FragNodes, remove one FragNode
  480.  * at random from the list, deallocate it, and return the fragment
  481.  * size that was deallocated.  Return NULL (0L) if the list is empty.
  482.  * -------------------------------------------------------------------- */
  483. LONG FreeRandomFrag (list)
  484.   struct MinList *list;
  485. {
  486.   LONG i, j;
  487.   struct FragNode *tnode;
  488.  
  489.   tnode = (struct FragNode *) list->mlh_Head;
  490.  
  491. /* Empty list? just return NULL */
  492.   if (tnode->fn_Node.mln_Succ == 0)
  493.     return (0L);
  494.   else
  495.   {
  496. /* Generate a random number N, such that 0 <= N < AllocCount/2 */
  497.     j = (LONG) RangeRand ((ULONG)AllocCount >> 1);
  498.  
  499. /* Walk through the MinList N elements, restarting at lh_Head if we
  500.  * hit the end of the list before finding the Nth node.
  501.  */
  502.     for (i = 0; i < j; i++)
  503.     {
  504.       tnode = (struct FragNode *) tnode->fn_Node.mln_Succ;
  505.       if (tnode->fn_Node.mln_Succ == 0)
  506.         tnode = (struct FragNode *) list->mlh_Head;
  507.     }
  508.  
  509. /* Remove this node from the list, grab it's size and deallocate */
  510.     Remove ((struct Node *)tnode);
  511.     i = (LONG)tnode->fn_Size;
  512.  
  513. #ifdef DEBUGIT
  514.     printf ("Freeing %7ld byte frag ($%08lx)\n", i, tnode);
  515. #endif
  516.  
  517.     FreeFragNode (tnode);
  518.     AllocCount--;
  519.     TotalFragBytes -= i;
  520.  
  521. /* Return the actual size of fragment deallocated */
  522.     return (i);
  523.   }
  524. }
  525.  
  526. /* --------------------------------------------------------------------
  527.  * Show current fragmentation and memory statistics in FragWin window
  528.  * -------------------------------------------------------------------- */
  529. VOID PrintMemoryStats()
  530. {
  531.   static BYTE fmtstr1[] = "%9ld %9ld %10ld";
  532.   static BYTE fmtstr2[] = "%7ld   %7ld";
  533.  
  534.   BYTE tstr[80];
  535.   LONG chipavail, chiplargest;
  536.   LONG fastavail, fastlargest;
  537.   LONG totalavail, abslargest;
  538.   struct RastPort *rp;
  539.  
  540.   chipavail = (LONG)AvailMem ((LONG)MEMF_CHIP);
  541.   chiplargest = (LONG)AvailMem ((LONG)(MEMF_CHIP|MEMF_LARGEST));
  542.   fastavail = (LONG)AvailMem ((LONG)MEMF_FAST);
  543.   fastlargest = (LONG)AvailMem ((LONG)(MEMF_FAST|MEMF_LARGEST));
  544.  
  545.   totalavail = chipavail + fastavail;
  546.   if (chiplargest > fastlargest)
  547.     abslargest = chiplargest;
  548.   else
  549.     abslargest = fastlargest;
  550.   
  551.   sprintf (tstr, fmtstr1, AllocCount, FailCount, TotalFragBytes);
  552.   rp = FragWin->RPort;
  553.  
  554.   SetAPen (rp, 1L);
  555.   Move (rp, (LONG)FHDTL, (LONG)FHDTT);
  556.   Text (rp, tstr, (LONG) strlen (tstr));
  557.  
  558.   sprintf (tstr, fmtstr2, chipavail, chiplargest);
  559.   Move (rp, (LONG)(FHDTL+84), (LONG)(FHDTT+20));
  560.   Text (rp, tstr, (LONG) strlen (tstr));
  561.  
  562.   sprintf (tstr, fmtstr2, fastavail, fastlargest);
  563.   Move (rp, (LONG)(FHDTL+84), (LONG)(FHDTT+30));
  564.   Text (rp, tstr, (LONG) strlen (tstr));
  565.  
  566.   sprintf (tstr, fmtstr2, totalavail, abslargest);
  567.   Move (rp, (LONG)(FHDTL+84), (LONG)(FHDTT+40));
  568.   Text (rp, tstr, (LONG) strlen (tstr));
  569. }
  570.  
  571.  
  572. /* --------------------------------------------------------------------
  573.  * Allocate all memory down to MinMem threshold.
  574.  */
  575. VOID AllocAllMem (list, limit)
  576.   struct MinList *list;
  577.   LONG limit;
  578. {
  579.   struct FragNode *tnode;
  580.   LONG csize, tsize;
  581.  
  582. /* While available memory is greater than Min threshold...*/
  583.   while ((csize = AvailMem((LONG)FMemType)) > limit)
  584.   {
  585.  
  586. /* What is the largest block available for allocation? */
  587.     tsize = AvailMem ((LONG)(MEMF_LARGEST | FMemType));
  588.  
  589. /* If the largest block is larger than min frag size, allocate less. */
  590.     if (tsize > FMaxFrag)
  591.       tsize = FMaxFrag;
  592.  
  593. /* If allocating a new min frag would put us below min level, allocate
  594.  * only what we need.
  595.  */
  596.     if ((csize - tsize) < limit)
  597.       tsize = csize - limit;
  598.  
  599. /* Allocate the new node, if there is sufficient memory */
  600.     if (tsize >= 0 && (tnode = AllocFragNode (tsize)) != 0)
  601.     {
  602.       AddHead ((struct List *)list, (struct Node *)tnode);
  603.   
  604. #ifdef DEBUGIT
  605.       printf("Adding a %7ld byte frag SUCCEEDED\n", tsize);
  606. #endif
  607.       AllocCount++;
  608.  
  609. /* Add to allocation totals, account for struct size! */
  610.       TotalFragBytes += tsize;
  611.       if ((AllocCount % 100) == 0)
  612.         PrintMemoryStats ();
  613.  
  614. /* See if there is a message at the window...might want to abort */
  615.       if (FragWin->UserPort->mp_MsgList.lh_Head->ln_Succ != 0)
  616.         return;
  617.     }
  618.     else
  619.     {
  620. #ifdef DEBUGIT
  621.       printf("Adding a %7ld byte frag FAILED!\n", tsize);
  622. #endif
  623.       FailCount++;
  624.       return;        /* Shouldn't Fail since we asked for a known size */
  625.     }
  626.   }
  627. }
  628.  
  629. /* --------------------------------------------------------------------
  630.  * Play with random sized memory chunks, where:
  631.  *   minfrag <= random size <= maxfrag
  632.  * -------------------------------------------------------------------- */
  633. VOID ThrashMem(minmem, minfrag, maxfrag)
  634.   LONG minmem, minfrag, maxfrag;
  635. {
  636.   LONG tmem, lfrag;
  637.  
  638. /* If available ram is greater than "minmem", attempt to allocate a random
  639.  * sized fragment and add it to the MinList.  Otherwise, free an entry
  640.  * picked at random from the linked-list of FragNodes.
  641.  */
  642.   tmem = AvailMem ((LONG)FMemType);
  643.   lfrag = AvailMem ((LONG)(MEMF_LARGEST | FMemType));
  644.  
  645.   if (tmem < minmem || lfrag < minfrag)
  646.   {
  647.     (VOID) FreeRandomFrag (FragList);
  648.   }
  649.   else
  650.   {
  651.     if (maxfrag > lfrag)
  652.       maxfrag = lfrag;
  653.     (VOID) AddRandomFrag (FragList, minfrag, maxfrag);
  654.   }
  655. }
  656.  
  657. /* --------------------------------------------------------------------
  658.  * Given a pointer to a Boolean gadget, determine which function to perform.
  659.  * -------------------------------------------------------------------- */
  660. VOID DoFragBoolGad (tgad)
  661.   struct Gadget *tgad;
  662. {
  663.   switch (tgad->GadgetID)
  664.   {
  665.     case 20:    /* STOP */
  666.       FragGoFlag = 0;
  667.       break;
  668.     case 21:    /* START */
  669.       FragGoFlag = 1;
  670.       break;
  671.     case 22:    /* ALLOC */
  672.       AllocAllMem (FragList, FMinMem);
  673.       PrintMemoryStats ();
  674.       break;
  675.     case 23:    /* PURGE */
  676.       FreeAllFragNodes (FragList);
  677.       AllocCount = FailCount = TotalFragBytes = 0;
  678.       PrintMemoryStats ();
  679.       break;
  680.   }
  681. }
  682.  
  683. /* --------------------------------------------------------------------
  684.  * Given a pointer to a string gadget, determine which number to update.
  685.  * Bound check new number appropriately.
  686.  * -------------------------------------------------------------------- */
  687. VOID DoFragStringGad (tgad)
  688.   struct Gadget *tgad;
  689. {
  690.   LONG temp;
  691.   LONG *dest;
  692.   LONG nmin, nmax;
  693.  
  694.   temp = ((struct StringInfo *)tgad->SpecialInfo)->LongInt;
  695.   nmin = 0;
  696.   nmax = 0x00ffffffL;
  697.   switch (tgad->GadgetID)
  698.   {
  699.     case 10:    /* FMinMemGad */
  700.       dest = &FMinMem;
  701.       break;
  702.     case 11:    /* FAllocSpeedGad */
  703.       dest = &FAllocSpeed;
  704.       nmin = 1;
  705.       break;
  706.     case 12:    /* FMinFragGad */
  707.       dest = &FMinFrag;
  708.       nmin = FSIZE;
  709.       nmax = FMaxFrag;
  710.       break;
  711.     case 13:    /* FMaxFragGad */
  712.       dest = &FMaxFrag;
  713.       nmin = FMinFrag;
  714.       break;
  715.   }
  716.  
  717.   if (temp < nmin)
  718.     temp = nmin;
  719.   else if (temp > nmax)
  720.     temp = nmax;
  721.   sprintf (((struct StringInfo *)tgad->SpecialInfo)->Buffer, LongFmtStr, temp);
  722.   RefreshGList (tgad, FragWin, 0L, 1L);
  723.   *dest = temp;
  724.  
  725. /* If user changed the Speed, abort old timer request and queue new one */
  726.   if (tgad->GadgetID == 11)
  727.   {
  728.     AbortAsyncIO (TimerPort1, (struct IORequest *)STimeReq);
  729.     SetMicroTimer (FAllocSpeed);
  730.   }
  731. }
  732.  
  733. /* --------------------------------------------------------------------
  734.  * Function to process FragWin IDCMP messages received.  If we receive
  735.  * a VANILLAKEY == ESCAPE or CLOSEWINDOW event, set the global FragDone flag.
  736.  * -------------------------------------------------------------------- */
  737. VOID DoFragIDCMP ()
  738. {
  739.   struct Gadget *tgadget;
  740.   struct IntuiMessage *imsg;
  741.   ULONG class;
  742.   ULONG code;
  743.  
  744.   while ((imsg = (struct IntuiMessage *) GetMsg (FragWin->UserPort)) != 0)
  745.   {
  746.     class = imsg->Class;
  747.     code = imsg->Code;
  748.     tgadget = (struct Gadget *)imsg->IAddress;
  749.     ReplyMsg ((struct Message *)imsg);
  750.  
  751.     switch (class)
  752.     {
  753.       case GADGETUP:
  754.        ((VOID (*) __fARGS((struct Gadget *)))tgadget->UserData)(tgadget);
  755.         break;
  756.       case VANILLAKEY:
  757.         switch (code)
  758.         {
  759.           case 'a':    /* 'a' for Alloc */
  760.             DoFragBoolGad (&FAllocGad);
  761.             break;
  762.           case 'p':    /* 'p' for Purge */
  763.             DoFragBoolGad (&FPurgeGad);
  764.             break;
  765.           case 's':    /* 's' - Start/Stop */
  766.           case ' ':    /* SPACE */
  767.             FragGoFlag ^= 1;
  768.             break;
  769.           case 0x1b:    /* ESC - quit */
  770.             FragDone = 1;
  771.             break;
  772. #ifdef DEBUGIT
  773.           default:
  774.         printf ("Unknown VANILLAKEY char: $%02ld\n", (LONG)code);
  775.         break;
  776. #endif
  777.           
  778.         }
  779.         break;
  780.       case CLOSEWINDOW:
  781.         FragDone = 1;
  782.         break;
  783.     }
  784.   }
  785. }
  786.  
  787. /* -------------------------------------------------------------------- */
  788. LONG CreateVBTimer (name, pport, ptreq)
  789.   BYTE *name;
  790.   struct MsgPort **pport;
  791.   struct timerequest **ptreq;
  792. {
  793.   if ((*pport = CreatePort (name, 0L)) != 0)
  794.   {
  795.     if ((*ptreq = (struct timerequest *) CreateExtIO (*pport, (LONG)sizeof(struct timerequest))) != 0)
  796.     {
  797.       if (OpenDevice (TIMERNAME, (LONG)UNIT_VBLANK, (struct IORequest *)*ptreq, 0L) == 0)
  798.       {
  799.         return (1L);
  800.       }
  801.     }
  802.   }
  803.   return (0L);
  804. }
  805.  
  806. /* --------------------------------------------------------------------
  807.  * Queue a timer request for delay microseconds
  808.  * -------------------------------------------------------------------- */
  809. VOID SetMicroTimer (delay)
  810.   LONG delay;
  811. {
  812.   STimeReq->tr_node.io_Command = TR_ADDREQUEST;
  813.   STimeReq->tr_time.tv_secs = delay / 1000000L;
  814.   STimeReq->tr_time.tv_micro = delay % 1000000L;
  815.   SendIO ((struct IORequest *)STimeReq);
  816. }
  817.  
  818. /* --------------------------------------------------------------------
  819.  * Initialize timer devices
  820.  * --------------------------------------------------------------------    */
  821. VOID InitTimer ()
  822. {
  823.   if (CreateVBTimer (0L, &TimerPort1, &STimeReq) == 0)
  824.     CleanUp (140L);
  825.  
  826. /* Set wakeup signal mask for the timer ports */
  827.   FragTimerMask = 1L << TimerPort1->mp_SigBit;
  828.  
  829. /* Queue up first timer request */
  830.   SetMicroTimer (100L);
  831. }
  832.  
  833. /* --------------------------------------------------------------------
  834.  * Attempt to make RangeRand() a little less predictable between runs.
  835.  * -------------------------------------------------------------------- */
  836. VOID RattleDice ()
  837. {
  838.   LONG i, j;
  839.   struct DateStamp stime;
  840.   ULONG seedval;
  841.  
  842.   DateStamp ((LONG *)&stime);
  843.   seedval = stime.ds_Tick;
  844.   j = (LONG)(RangeRand (seedval + 0xaa) & 0xffL);
  845.   for (i = 0; i < j; i++)
  846.     (VOID) RangeRand (seedval);
  847. }
  848.  
  849. /* --------------------------------------------------------------------
  850.  * Allocate and initialize a MinList structure, return pointer to same.
  851.  * -------------------------------------------------------------------- */
  852. struct MinList *AllocMinList ()
  853. {
  854.   struct MinList *mlist;
  855.  
  856.   mlist = (struct MinList *) AllocMem ((LONG)sizeof(struct MinList), (LONG)FMemType);
  857.   if (mlist != 0)
  858.     NewList ((struct List *) mlist);
  859.   return (mlist);
  860. }
  861.  
  862. /* --------------------------------------------------------------------
  863.  * Given pointer to a filename, parse the Tool Type array of its,
  864.  * associated icon, if any, and set Fragit parameters
  865.  * accordingly.
  866.  * -------------------------------------------------------------------- */
  867. VOID ParseToolTypes(wbmsg)
  868.   BYTE *wbmsg;
  869. {
  870.   BYTE *cp;
  871.   struct DiskObject *dop;
  872.  
  873.   if ((IconBase = OpenLibrary ("icon.library", 33L)) == 0L)
  874.     CleanUp(122L);
  875.  
  876.   if ((dop = GetDiskObject(wbmsg)) != 0)
  877.   {
  878.  
  879.     if ((cp = FindToolType(dop->do_ToolTypes, "MINMEM")) != 0)
  880.     {
  881.       FMinMem = atol (cp);
  882.       if (FMinMem < 0)
  883.         FMinMem = 0;
  884.     }
  885.  
  886.     if ((cp = FindToolType(dop->do_ToolTypes, "MINFRAG")) != 0)
  887.     {
  888.       FMinFrag = atol (cp);
  889.       if (FMinFrag < FSIZE)
  890.         FMinFrag = FSIZE;
  891.     }
  892.  
  893.     if ((cp = FindToolType(dop->do_ToolTypes, "MAXFRAG")) != 0)
  894.     {
  895.       FMaxFrag = atol (cp);
  896.       if (FMaxFrag < FMinFrag)
  897.         FMaxFrag = FMinFrag;
  898.     }
  899.  
  900.     if ((cp = FindToolType(dop->do_ToolTypes, "SPEED")) != 0)
  901.       FAllocSpeed = atol (cp);
  902.  
  903.     if (FindToolType(dop->do_ToolTypes, "CHIP") != 0)
  904.       FMemType = MEMF_CHIP;
  905.  
  906.     if (FindToolType(dop->do_ToolTypes, "FAST") != 0)
  907.       FMemType = MEMF_FAST;
  908.  
  909.     if ((cp = FindToolType(dop->do_ToolTypes, "MEMTYPE")) != 0)
  910.       FMemType = atol (cp);
  911.  
  912. /* Free the DiskObject pointer */
  913.     FreeDiskObject(dop);
  914.   }
  915.   CloseLibrary (IconBase);
  916.   IconBase = 0;
  917. }
  918.  
  919. /* --------------------------------------------------------------------
  920.  * Fragit program main entry point.
  921.  * -------------------------------------------------------------------- */
  922. VOID main(argc, argv)
  923.   int argc;
  924.   BYTE **argv;
  925. {
  926.   struct WBStartup *wbm;
  927.   ULONG signals;
  928.  
  929. /* Open libraries */
  930.   if ( (GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0L)) == 0)
  931.     CleanUp (120L);
  932.   if ( (IntuitionBase = (struct IntuitionBase *)OpenLibrary ("intuition.library", 0L)) == 0)
  933.     CleanUp (121L);
  934.  
  935. /* Allocate and initialize MinList of FragNode fragments */
  936.   if ((FragList = AllocMinList ()) == 0)
  937.     CleanUp (103L);
  938.  
  939. /* Set defaults */
  940.   FMinMem = 100000L;        /* Minimum memory limit = 100K */
  941.   FMinFrag = FSIZE;        /* Minimum fragment size = node size */
  942.   FMaxFrag = 50000L;        /* Maximum fragment size = 50K */
  943.   FAllocSpeed = 50000L;        /* 0.05 secs between allocs */
  944.   FMemType = 0L;        /* Any Memory */
  945.  
  946.   if (argc == 0) /* It's from Workbench, see if there are tooltypes */
  947.   {
  948.     wbm = (struct WBStartup *)argv;
  949.     ParseToolTypes (wbm->sm_ArgList->wa_Name);
  950.   }
  951.   else         /* It's from CLI, see if the ICON is around for INFO anyhow */
  952.   {
  953.     ParseToolTypes (argv[0]);
  954.   }
  955.  
  956. #ifdef DEBUGIT
  957.   printf ("MinMemLevel: %ld MinFragSize: %ld MaxFragSize: %ld\n", FMinMem, FMinFrag, FMaxFrag);
  958.   Delay (50L);
  959. #endif
  960.  
  961. /* Init RangeRand() seed */
  962.   RattleDice ();
  963.  
  964. /* Initialize timer device */
  965.   InitTimer ();
  966.  
  967. /* Initialize string gadget texts */
  968.   sprintf (FMinMemStr, LongFmtStr, FMinMem);
  969.   sprintf (FAllocSpeedStr, LongFmtStr, FAllocSpeed);
  970.   sprintf (FMinFragStr, LongFmtStr, FMinFrag);
  971.   sprintf (FMaxFragStr, LongFmtStr, FMaxFrag);
  972.  
  973. /* Initialize gadget UserData fields to point to their handler functions */
  974.   FMinMemGad.UserData = (APTR)DoFragStringGad;
  975.   FAllocSpeedGad.UserData = (APTR)DoFragStringGad;
  976.   FMinFragGad.UserData = (APTR)DoFragStringGad;
  977.   FMaxFragGad.UserData = (APTR)DoFragStringGad;
  978.  
  979.   FStopGad.UserData = (APTR)DoFragBoolGad;
  980.   FStartGad.UserData = (APTR)DoFragBoolGad;
  981.   FAllocGad.UserData = (APTR)DoFragBoolGad;
  982.   FPurgeGad.UserData = (APTR)DoFragBoolGad;
  983.  
  984. /* Open control window */
  985.   if ((FragWin = OpenWindow (&NewFragWin)) == 0)
  986.     CleanUp (130L);
  987.   FragIDCMPMask = 1L << FragWin->UserPort->mp_SigBit;
  988.  
  989. /* Handle IDCMP events till done... */
  990.   while (FragDone == 0)
  991.   {
  992.     signals = Wait ((LONG)(FragIDCMPMask | FragTimerMask));
  993.  
  994.     if ((signals & FragTimerMask) != 0)
  995.     {
  996.       if (GetMsg (TimerPort1) != 0)
  997.       {
  998.         SetMicroTimer (FAllocSpeed);
  999.         if (FragGoFlag != 0)
  1000.           ThrashMem (FMinMem, FMinFrag, FMaxFrag);
  1001.         PrintMemoryStats ();
  1002.       }
  1003.     }
  1004.     if ((signals & FragIDCMPMask) != 0)
  1005.       DoFragIDCMP ();
  1006.   }
  1007.  
  1008. /* All done, free everything */
  1009.   CleanUp (0L);
  1010. }
  1011.